/**
 *  第一版，使用数组缓存，shift删除开头第一项
 */
const fs = require('fs');
const EventsEmitter = require('events');

/* class Writable extends EventsEmitter {
  constructor(options) {
    super();
    this.len = 0; // 需要统计的长度累加
  }
  write() {
    this._write();
  }
} */

class WriteStream extends EventsEmitter {
  constructor(path, options = {}) {
    super(options);
    this.path = path;
    this.flags = options.flags || 'w';
    this.encoding = options.encoding || 'utf8';
    this.autoClose = options.autoClose || true;
    this.highWaterMark = options.highWaterMark || 16 * 1024;

    this.open();

    // writing 要判断是第一次写还是第二次写入，第一次是写入真实文件，后续是写到内存中
    this.writing = false; // 用来描述当前是否有正在写入的操作
    this.needDrain = false; // 默认是否触发 drain 事件
    this.len = 0; // 需要统计的长度累加
    this.offset = 0; // 每次写入的时的偏移量
    this.cache = []; // 实现缓存的
  }
  open() {
    fs.open(this.path, this.flags, (err, fd) => {
      if (err) return this.emit('error', err);
      this.fd = fd;
      this.emit('open', fd);
    });
  }
  // 用户调用的方法
  write(chunk, encoding = this.encoding, cb = () => {}) {
    // 需要判断是真的写入磁盘还是写入内存
    chunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
    this.len += chunk.length;
    let ret = this.len < this.highWaterMark;
    if (!ret) {
      // 达到预期，或者超过预期，就改变触发 drian 事件
      this.needDrain = true;
    }

    if (this.writing) {
      // 第二次就放置缓存
      // 如果正在写入就先缓存起来,稍后再入写入
      this.cache.push({
        chunk,
        encoding,
        cb,
      });
    } else {
      // 第一次就写入磁盘
      this.writing = true; // 标识正在写入
      this._write(chunk, encoding, () => {
        // 写完之后就，先执行用户的回调，清空缓存里面的队列
        cb();
        this.clearBuffer();
      });
    }

    return ret;
  }
  // 多个异步并发，可以用队列来实现，依次清空
  clearBuffer() {
    let data = this.cache.shift();
    if (data) {
      let { chunk, encoding, cb } = data;
      this._write(chunk, encoding, () => {
        cb();
        this.clearBuffer();
      });
    } else {
      this.writing = false; // 缓存中的内容也要写入了，清空缓存
      if (this.needDrain) {
        this.needDrain = false;
        this.emit('drain');
      }
    }
  }
  _write(chunk, encoding, cb) {
    // 因为是异步的，所以是订阅
    if (typeof this.fd !== 'number') {
      return this.once('open', () => this._write(chunk, encoding, cb));
    }
    // 真实写入磁盘，系统的
    console.log(this.fd);
    fs.write(this.fd, chunk, 0, chunk.length, this.offset, (err, written) => {
      this.len -= written;
      this.offset += written;
      cb();
    });
  }
}
module.exports = WriteStream;
